package com.example.apidocserver.domain.user.event.impl;

import com.example.apidocserver.application.dto.UserDocInfoDto;
import com.example.apidocserver.domain.user.entity.DocUsrHis;
import com.example.apidocserver.domain.user.event.UserDocInfoEventService;
import com.example.apidocserver.domain.user.service.DocUsrHisService;
import com.example.apidocserver.infrastructure.util.user.CurrentUser;
import com.example.apidocserver.infrastructure.config.security.UserDetailsImpl;
import com.example.apidocserver.infrastructure.enums.HisIdEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 用户认证授权服务
 *
 * @author xyqlg
 */
@Service
@Slf4j
public class UserDocInfoEventServiceImpl implements UserDocInfoEventService {
    @Resource
    private DocUsrHisService docUsrHisService;

    private final Map<Long, DocUsrHis> idHisMap = new HashMap<>(8);

    @Override
    public DocUsrHis getUsrLastInfo() {
        UserDetailsImpl user = CurrentUser.getUser();
        if (Objects.isNull(user) || Objects.isNull(user.getUserId())) {
            return null;
        }
        if (idHisMap.containsKey(user.getUserId())) {
            return idHisMap.get(user.getUserId());
        }
        DocUsrHis docUsrHis = docUsrHisService.queryLastByUserId(user.getUserId());
        if (Objects.nonNull(docUsrHis)) {
            idHisMap.put(docUsrHis.getUsrId(), docUsrHis);
        } else {
            docUsrHis = new DocUsrHis().setUsrId(user.getUserId());
        }
        log.info("his:{}", docUsrHis);
        return docUsrHis;
    }

    @Override
    public void setHisId(DocUsrHis docUsrHisIn, HisIdEnum hisIdEnum) {
        log.info("his input: {}", docUsrHisIn);
        if (Objects.isNull(docUsrHisIn.getId())) {
            docUsrHisService.insert(docUsrHisIn);
        }
        DocUsrHis usrHis = new DocUsrHis().setUsrId(docUsrHisIn.getUsrId());
        switch (hisIdEnum) {
            case ALL:
                docUsrHisService.update(docUsrHisIn);
                return;
            case SPACE:
                refreshSpace(docUsrHisIn, usrHis);
                return;
            case DOC:
                refreshDoc(docUsrHisIn, usrHis);
                return;
            case API:
                refreshApi(docUsrHisIn, usrHis);
                return;
            case ENV:
                refreshEnv(docUsrHisIn, usrHis);
                return;
            case HIS:
                refreshHis(docUsrHisIn, usrHis);
                return;
            default:
                log.error("入参枚举错误");
        }
    }

    @Override
    public DocUsrHis getUsrLastInfoBySpace(Integer spaceId) {
        UserDetailsImpl user = CurrentUser.getUser();
        DocUsrHis docUsrHis = new DocUsrHis();
        if (Objects.isNull(user) || Objects.isNull(user.getUserId())) {
            return docUsrHis;
        }

        docUsrHis.setSpaceId(spaceId).setUsrId(user.getUserId());
        DocUsrHis dbUserHis = docUsrHisService.queryLastByEntity(docUsrHis);
        if (Objects.isNull(dbUserHis)) {
            {
                idHisMap.put(user.getUserId(), docUsrHis);
                return docUsrHis;
            }
        }
        idHisMap.put(user.getUserId(), dbUserHis);
        log.info("his:{}", docUsrHis);
        return dbUserHis;
    }

    @Override
    public DocUsrHis getUsrLastInfoByDocEnv() {
        // 查询空间下文档对应环境历史数据
        DocUsrHis usrLastInfo = getUsrLastInfo();
        DocUsrHis query = new DocUsrHis().setSpaceId(usrLastInfo.getSpaceId()).setDocId(usrLastInfo.getDocId())
                .setEnvId(usrLastInfo.getEnvId()).setUsrId(usrLastInfo.getUsrId());
        DocUsrHis db = docUsrHisService.queryLastByEntity(query);

        if (Objects.isNull(db)) {
            // 不存在则查询文档最后访问数据
            query.setEnvId(null);
            db = docUsrHisService.queryLastByEntity(query);
            if (Objects.isNull(db)) {
                // 文档无访问记录，则按新访问处理
                db = query.setEnvId(usrLastInfo.getEnvId());
            }
        }
        idHisMap.put(usrLastInfo.getUsrId(), db);
        log.info("his:{}", db);
        return db;
    }

    private void refreshSpace(DocUsrHis docUsrHisIn, DocUsrHis usrHis) {
        usrHis.setSpaceId(docUsrHisIn.getSpaceId());
        DocUsrHis docDb = docUsrHisService.queryLastByEntity(usrHis);
        if (Objects.nonNull(docDb)) {
            docUsrHisService.update(docDb);
            idHisMap.put(docDb.getUsrId(), docDb);
            return;
        }
        docUsrHisService.insert(usrHis.setId(null));
        idHisMap.put(usrHis.getUsrId(), usrHis);
        log.info("space update: {}", usrHis);
    }

    private void refreshDoc(DocUsrHis docUsrHisIn, DocUsrHis usrHis) {
        DocUsrHis docDb = docUsrHisService.queryLastByEntity(usrHis.setSpaceId(docUsrHisIn.getSpaceId())
                .setDocId(docUsrHisIn.getDocId()));
        if (Objects.nonNull(docDb)) {
            setEnv(docDb, docUsrHisIn);
            // 存在，需要需要对比数据是否存在
            upsertHis(docDb, docUsrHisIn);
            return;
        }
        usrHis.setApiId(docUsrHisIn.getApiId()).setHisId(docUsrHisIn.getHisId()).setHisId(docUsrHisIn.getHisId());
        docUsrHisService.insert(usrHis);
        idHisMap.put(usrHis.getUsrId(), usrHis);
    }

    private void refreshApi(DocUsrHis docUsrHisIn, DocUsrHis usrHis) {
        DocUsrHis docDb = docUsrHisService.queryLastByEntity(usrHis.setSpaceId(docUsrHisIn.getSpaceId())
                .setDocId(docUsrHisIn.getDocId()).setApiId(usrHis.getApiId()));
        if (Objects.nonNull(docDb)) {
            setEnv(docDb, docUsrHisIn);
            // 存在，需要需要对比数据是否存在
            upsertHis(docDb, docUsrHisIn);
            return;
        }
        usrHis.setEnvId(docUsrHisIn.getEnvId()).setHisId(docUsrHisIn.getHisId());
        docUsrHisService.insert(usrHis.setId(null));
        idHisMap.put(usrHis.getUsrId(), usrHis);
    }

    private void refreshEnv(DocUsrHis docUsrHisIn, DocUsrHis usrHis) {
        DocUsrHis docDb = docUsrHisService.queryLastByEntity(usrHis.setSpaceId(docUsrHisIn.getSpaceId())
                .setDocId(docUsrHisIn.getDocId()).setApiId(docUsrHisIn.getApiId()).setEnvId(docUsrHisIn.getEnvId()));
        if (Objects.nonNull(docDb)) {
            // 存在，需要需要对比数据是否存在
            upsertHis(docDb, docUsrHisIn);
            return;
        }
        usrHis.setHisId(docUsrHisIn.getHisId()).setId(null);
        docUsrHisService.insert(usrHis);
        idHisMap.put(usrHis.getUsrId(), usrHis);
        log.info("env update: {}", usrHis);
    }

    private void refreshHis(DocUsrHis docUsrHisIn, DocUsrHis usrHis) {
        DocUsrHis docDb;
        Integer id = docUsrHisIn.getId();
        Integer hisId = docUsrHisIn.getHisId();
        docUsrHisIn.setId(null).setHisId(null).setCreateTime(null).setUpdateTime(null).setCreator(null).setUpdater(null);
        docDb = docUsrHisService.queryLastByEntity(docUsrHisIn);
        if (Objects.nonNull(docDb)) {
            setEnv(docDb, docUsrHisIn);
            idHisMap.put(docDb.getUsrId(), docDb.setId(id).setHisId(hisId));
            docUsrHisService.update(docDb);
            return;
        }
        docUsrHisService.insert(docUsrHisIn.setId(null));
        idHisMap.put(usrHis.getUsrId(), docUsrHisIn);
        log.info("his update: {}", docUsrHisIn);
    }

    /**
     * 是已有数据
     *
     * @param docDb  数据库数据
     * @param usrHis 入参数据
     */
    private void upsertHis(DocUsrHis docDb, DocUsrHis usrHis) {
        if (Objects.equals(docDb.getSpaceId(), usrHis.getSpaceId())
                && Objects.equals(docDb.getDocId(), usrHis.getDocId())
                && Objects.equals(docDb.getApiId(), usrHis.getApiId())
                && Objects.equals(docDb.getEnvId(), usrHis.getEnvId())) {
            docDb.setHisId(usrHis.getHisId());
            docUsrHisService.update(docDb);
            idHisMap.put(usrHis.getUsrId(), docDb);
        } else {
            DocUsrHis query = new DocUsrHis();
            query.setSpaceId(usrHis.getSpaceId()).setDocId(usrHis.getDocId()).setApiId(usrHis.getApiId())
                    .setEnvId(usrHis.getEnvId());
            DocUsrHis docDbNew = docUsrHisService.queryLastByEntity(query);
            if (Objects.nonNull(docDbNew)) {
                docDbNew.setHisId(usrHis.getHisId());
                docUsrHisService.update(docDbNew);
                idHisMap.put(usrHis.getUsrId(), docDbNew);
            } else {
                usrHis.setId(null);
                docUsrHisService.insert(usrHis);
                idHisMap.put(usrHis.getUsrId(), usrHis);
            }
        }
    }

    private void setEnv(DocUsrHis docDb, DocUsrHis docUsrHisIn) {
        if (Objects.nonNull(docUsrHisIn.getEnvId()) && Objects.isNull(docDb.getEnvId())) {
            docDb.setEnvId(docUsrHisIn.getEnvId());
        }
    }
}
